//@author A0086393U
package rightnow.ui.widgets;

import java.util.Observable;

/**
 * This class provides the functionality of Quick Help. It gets the first
 * word of an input string and determines the HelpCode by looking at what
 * characters that word begins with. The HelpCode is then used to retrieve
 * the appropriate string to display, and then sets it in the feedback box.
 * 
 * Uses the singleton pattern and is Observable, so FeedbackController
 * can be notified when QuickHelp's message changes.
 */
public class QuickHelp extends Observable {

	private enum HelpCode {
		DEFAULT, INDEX, ADD, EDIT, DELETE, LIST, DONE, LS, D, N, NOW, NEXT, REDO, 
		P, PIN, UN, PREV, PAGE, UND, UNPIN, NULL, UNDONE, PG
	};

	/* Strings to display to user */
	private static final String HELP_DEFAULT = 	"Commands: 'add', 'edit', "
			+ "'delete', 'pin', 'done', 'list', 'now', '<index #>'.";
	private static final String HELP_INDEX = 		"'<index #>' to toggle details of "
			+ "that task.";
	private static final String HELP_ADD = 			"'add <desc.> at <s/time> on "
			+ "<s/date> by <e/time> on <e/date>'.";
	private static final String HELP_LIST = 		"'list <search term>' to search "
			+ "or 'list' to list all tasks.";
	private static final String HELP_EDIT = 		"'edit <index #>' to edit that "
			+ "task.";
	private static final String HELP_DELETE = 	"'delete <index #>', "
			+ "or 'delete done' to delete all done tasks.";
	private static final String HELP_LS = 			"'ls <search term>' to search or "
			+ "'ls' to list all tasks.";
	private static final String HELP_DONE = 		"'done <index #>' to mark that "
			+ "task as done.";
	private static final String HELP_D = 				"Available commands: 'delete', "
			+ "'done'.";
	private static final String HELP_N = 				"Available commands: 'next', "
			+ "'now'.";
	private static final String HELP_NOW = 			"'now' to show tasks available "
			+ "now.";
	private static final String HELP_NEXT = 		"'next' to go to the next page.";
	private static final String HELP_REDO = 		"'redo' to redo the previously "
			+ "undone action.";
	private static final String HELP_P = 				"Available commands: 'page', "
			+ "'pin', 'previous'.";
	private static final String HELP_PIN = 			"'pin <index #>' to pin that "
			+ "task.";
	private static final String HELP_PREV = 		"'previous' to go to "
			+ "the previous page.";
	private static final String HELP_PAGE = 		"'page <page #>' to jump to "
			+ "that page.";
	private static final String HELP_PG =				"'pg <page #>' to jump to that "
			+ "page.";
	private static final String HELP_UN = 			"Available commands: 'undo', "
			+ "'undone', 'unpin'.";
	private static final String HELP_UNPIN = 		"'unpin <index #>' to unpin "
			+ "that task.";
	private static final String HELP_UND = 			"Available commands: 'undo' to "
			+ "undo previous action, 'undone'.";
	private static final String HELP_UNDONE =		"'undone <index #>' to mark "
			+ "that task as not done.";
	
	private static final String INDEX_REGEX = "[1-7]";
	
	private static QuickHelp instance = new QuickHelp();
	private String message;
	
	private QuickHelp() {
		super();
		
		message = null;
	}
	
	protected static QuickHelp getInstance() {
		return instance;
	}
	
	protected void generateDefaultQuickHelpText() {
		setMessage(retrieveHelpText(HelpCode.DEFAULT));
	}
	
	/**
	 * This method will analyze what has been input so far and generate the
	 * appropriate text to display in Quick Help
	 * 
	 * @param input
	 *          String containing the current text in the command line
	 * @return String containing text to display in Quick Help
	 */
	protected void generateQuickHelp(String input) {
		// Decide what help text to generate based on the first word of input
		// Only set feedback message if the help text retrieved is not null
		HelpCode helpCode = getHelpCode(getFirstWord(input));
		String helpText = retrieveHelpText(helpCode);
		if (helpText != null) {
			setMessage(helpText);
		}
	}

	private String retrieveHelpText(HelpCode helpCode) {
		switch (helpCode) {
			case INDEX :
				return HELP_INDEX;
			case ADD :
				return HELP_ADD;
			case LIST :
				return HELP_LIST;
			case EDIT :
				return HELP_EDIT;
			case DELETE :
				return HELP_DELETE;
			case DEFAULT :
				return HELP_DEFAULT;
			case D :
				return HELP_D;
			case DONE :
				return HELP_DONE;
			case LS :
				return HELP_LS;
			case N :
				return HELP_N;
			case NEXT :
				return HELP_NEXT;
			case NOW :
				return HELP_NOW;
			case P :
				return HELP_P;
			case PAGE :
				return HELP_PAGE;
			case PG :
				return HELP_PG;
			case PIN :
				return HELP_PIN;
			case PREV :
				return HELP_PREV;
			case REDO :
				return HELP_REDO;
			case UN :
				return HELP_UN;
			case UND :
				return HELP_UND;
			case UNDONE :
				return HELP_UNDONE;
			case UNPIN :
				return HELP_UNPIN;
			case NULL :	// Fallthrough
			default :
				break;
		}
		
		return null;
	}

	private HelpCode getHelpCode(String firstWord) {
		// Display default message if there is nothing in the text box
		if (firstWord.equals("")) {
			return HelpCode.DEFAULT;
		}
		
		// Display index message if the first word is an index
		if (firstWord.matches(INDEX_REGEX)) {
			return HelpCode.INDEX;
		}
		
		// Match the first word to valid commands to determine the help message.
		// Match and return from most specific to least specific.
		
		firstWord = firstWord.toUpperCase();
		
		/* "A" commands */
		if (firstWord.startsWith("A")) {
			return HelpCode.ADD;
		}
		
		/* "E" commands */
		if (firstWord.startsWith("E")) {
			return HelpCode.EDIT;
		}
		
		/* "D" commands */
		if (firstWord.startsWith("DE")) {
			return HelpCode.DELETE;
		}
		
		if (firstWord.startsWith("DO")) {
			return HelpCode.DONE;
		}
		
		if (firstWord.startsWith("D")) {
			return HelpCode.D;
		}
		
		/* "L" commands */
		if (firstWord.startsWith("LS")) {
			return HelpCode.LS;
		}
		
		if (firstWord.startsWith("L")) {
			return HelpCode.LIST;
		}
		
		/* "N" commands */
		if (firstWord.startsWith("NE")) {
			return HelpCode.NEXT;
		}
		
		if (firstWord.startsWith("NO")) {
			return HelpCode.NOW;
		}
		
		if (firstWord.startsWith("N")) {
			return HelpCode.N;
		}
		
		/* "R" commands */
		if (firstWord.startsWith("R")) {
			return HelpCode.REDO;
		}
		
		/* "P" commands */
		if (firstWord.startsWith("PI")) {
			return HelpCode.PIN;
		}
		
		if (firstWord.startsWith("PR")) {
			return HelpCode.PREV;
		}
		
		if (firstWord.startsWith("PA")) {
			return HelpCode.PAGE;
		}
		
		if (firstWord.startsWith("PG")) {
			return HelpCode.PG;
		}
		
		if (firstWord.startsWith("P")) {
			return HelpCode.P;
		}
		
		/* "R" commands */
		if (firstWord.startsWith("R")) {
			return HelpCode.REDO;
		}
		
		/* "U" commands */
		if (firstWord.startsWith("UNDON")) {
			return HelpCode.UNDONE;
		}
		
		if (firstWord.startsWith("UND")) {
			return HelpCode.UND;
		}
		
		if (firstWord.startsWith("UNP")) {
			return HelpCode.UNPIN;
		}
		
		if (firstWord.startsWith("U")) {
			return HelpCode.UN;
		}
		
		return HelpCode.NULL;
	}

	private String getFirstWord(String input) {
		String commandTypeString = input.trim().split("\\s+")[0];
		return commandTypeString;
	}
	
	private void setMessage(String msg) {
		message = msg;
		setChanged();
		notifyObservers();
	}

	protected String getMessage() {
		return message;
	}
}
